#ifndef BLOCKNOREPEATLIST_H
#define BLOCKNOREPEATLIST_H

#include "common_global.h"
#include <QWaitCondition>
#include <QMutexLocker>
#include <QMutex>
#include <list>
#include <set>
#include <atomic>

template<typename K, typename D>
class BlockNoRepeatList
{
public:
    /**
     * @brief  BlockNoRepeatList 构造函数
     * @return
     */
    BlockNoRepeatList() { m_block = true; }

    /**
     * @brief  ~BlockNoRepeatList 析构函数
     * @return
     */
    ~BlockNoRepeatList() {}

public:
    /**
     * @brief  push 添加数据
     * @param  data
     * @return void
     */
    void push(K key, D data)
    {
        Item item;
        item.key = key;
        item.data = data;

        QMutexLocker locker(&m_mutex);

        if (m_whiteKeys.find(item.key) == m_whiteKeys.end())
        {
            for (std::list<Item>::iterator it = m_list.begin(); it != m_list.end();)
            {
                if (it->key == item.key)
                {
                    it = m_list.erase(it);
                }
                else
                {
                    it++;
                }
            }
        }
        m_list.push_back(item);

        m_cv.notify_all();
    }

    /**
     * @brief  pop 获取数据
     * @param  data 数据
     * @return bool
     */
    bool pop(D& data)
    {
        QMutexLocker locker(&m_mutex);

        while (m_block && m_list.empty())
        {
            m_cv.wait(&m_mutex, 5);
        }

        if (m_list.empty())
        {
            return false;
        }

        data = m_list.front().data;
        m_list.pop_front();

        return true;
    }

    /**
     * @brief   addWhiteKey 添加白名单
     * @param   key
     * @return  void
     */
    void addWhiteKey(K key)
    {
        QMutexLocker locker(&m_mutex);

        m_whiteKeys.insert(key);
    }

    /**
     * @brief  empty 队列是否为空
     * @return bool
     */
    bool empty()
    {
        QMutexLocker locker(&m_mutex);
        return m_list.empty();
    }

    /**
     * @brief  size 队列大小
     * @return size_t
     */
    size_t size()
    {
        QMutexLocker locker(&m_mutex);
        return m_list.size();
    }

    /**
     * @brief  clear 清空队列
     * @return void
     */
    void  clear()
    {
        QMutexLocker locker(&m_mutex);
        std::list<Item> empty;
        std::swap(empty, m_list);
    }

    /**
     * @brief  setBlock 设置pop是否阻塞
     * @param  block pop是否阻塞
     * @return void
     */
    void setBlock(const bool block)
    {
        m_block = block;
        QMutexLocker locker(&m_mutex);
        m_cv.notify_all();
    }

private:
    /**
     * @brief  数据子项
     */
    struct Item
    {
        K key;      ///< 数据唯一标识模版，需支持 ==
        D data;     ///< 数据
    };

private:
    /** 链表
     */
    std::list<Item> m_list;

    /** 白名单
     */
    std::set<K> m_whiteKeys;

    /** 锁
     */
    QMutex m_mutex;

    /** 条件变量
     */
    QWaitCondition m_cv;

    /** pop是否阻塞
     */
    std::atomic<bool> m_block;
};

#endif // BLOCKNOREPEATLIST_H
